package com.weiiew.recipeservice.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.weiiew.common.entity.cal.TranslationRecipe;
import com.weiiew.common.entity.cal.calRecipe;
import com.weiiew.common.entity.simple.DoublePair;
import com.weiiew.recipeservice.annotation.RecipeChangeCacheEvict;
import com.weiiew.recipeservice.mapper.RecipeBuildingMapper;
import com.weiiew.recipeservice.mapper.RecipeIngredientMapper;
import com.weiiew.recipeservice.mapper.RecipeMapper;
import com.weiiew.recipeservice.mapper.RecipeProductMapper;
import com.weiiew.common.entity.dto.Recipe;
import com.weiiew.common.entity.dto.RecipeBuilding;
import com.weiiew.common.entity.dto.RecipeIngredient;
import com.weiiew.common.entity.dto.RecipeProduct;
import com.weiiew.common.entity.simple.SimpleBuilding;
import com.weiiew.common.entity.simple.SimpleItem;
import com.weiiew.common.entity.vo.RecipeVO;
import com.weiiew.common.entity.qo.RecipeQo;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author 魏锴
 * @description 针对表【recipe】的数据库操作Service实现
 * @createDate 2024-01-28 01:49:55
 */
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class RecipeServiceImpl implements RecipeService {
    private final RecipeIngredientMapper recipeIngredientMapper;
    private final RecipeProductMapper recipeProductMapper;
    private final RecipeBuildingMapper recipeBuildingMapper;
    private final RecipeMapper baseMapper;

    private void saveRecipeRelation(Recipe vo) throws Exception {
        vo.getIngredients().forEach((ingredient) -> {
            RecipeIngredient ri = new RecipeIngredient();
            ri.setRecipeId(vo.getId());
            ri.setItemId(ingredient.getId());
            ri.setAmount(ingredient.getNumber());
            recipeIngredientMapper.insert(ri);
        });
        vo.getProducts().forEach((product) -> {
            RecipeProduct rp = new RecipeProduct();
            rp.setRecipeId(vo.getId());
            rp.setItemId(product.getId());
            rp.setAmount(product.getNumber());
            recipeProductMapper.insert(rp);
        });
        vo.getBuildings().forEach((building) -> {
            RecipeBuilding rb = new RecipeBuilding();
            rb.setRecipeId(vo.getId());
            rb.setBuildingId(building.getId());
            recipeBuildingMapper.insert(rb);
        });
    }

    @Override
    @RecipeChangeCacheEvict
    public void createRecipe(Recipe recipe, Long id, Integer version) throws Exception {
        baseMapper.insertRecipe(recipe);//保存配方本体
        // 检查产物中是否存在无默认配方的物品
        List<Integer> products = new ArrayList<>();
        recipe.getProducts().forEach(numberPair -> {
            baseMapper.setDefaultRecipeIfNull(numberPair.getId(), recipe.getId());
        });
        // 设置配方产物原材料合成建筑列表
        saveRecipeRelation(recipe);
    }

    @Override
    @RecipeChangeCacheEvict
    public void modifyRecipe(Recipe recipe, Long id, Integer version) throws Exception {
        recipeIngredientMapper.deleteByRecipe(recipe.getId());
        recipeProductMapper.deleteByRecipe(recipe.getId());
        recipeBuildingMapper.deleteByRecipe(recipe.getId());
        baseMapper.updateRecipe(recipe);//保存配方本体
        saveRecipeRelation(recipe);
    }

    @Override
    @RecipeChangeCacheEvict
    public boolean removeRecipe(Integer id, Integer version) {
        QueryWrapper<RecipeIngredient> iQueryWrapper = new QueryWrapper<RecipeIngredient>().eq("recipe_id", id);
        QueryWrapper<RecipeProduct> pQueryWrapper = new QueryWrapper<RecipeProduct>().eq("recipe_id", id);
        QueryWrapper<RecipeBuilding> bQueryWrapper = new QueryWrapper<RecipeBuilding>().eq("recipe_id", id);
        recipeIngredientMapper.delete(iQueryWrapper);
        recipeProductMapper.delete(pQueryWrapper);
        recipeBuildingMapper.delete(bQueryWrapper);
        List<Integer> items = baseMapper.getItemListByDefaultRecipe(id);
        for (int item : items) {
            Long newRecipe = baseMapper.getFirstRecipeByProductId(item, id);
            baseMapper.setDefaultRecipe(newRecipe, item);
        }
        baseMapper.deleteById(id);
        return true;
    }

    @Override
    @Cacheable(cacheNames = "recipe:list", key = "#qo.hasPageKey")
    public List<RecipeVO> getRecipeList(RecipeQo qo) {
        return baseMapper.getList(qo);
    }

    @Override
    @Cacheable(cacheNames = "recipe:length", key = "#qo.noPageKey")
    public Integer getRecipeLength(RecipeQo qo) {
        return baseMapper.getCount(qo);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:item:sort:product", key = "#version")
    public List<SimpleItem> getItemListSortByProduct(Integer version) {
        return baseMapper.getItemListSortByProduct(version);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:item:sort:ingredient", key = "#version")
    public List<SimpleItem> getItemListSortByIngredient(Integer version) {
        return baseMapper.getItemListSortByIngredient(version);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:build:sort:product", key = "#version")
    public List<SimpleBuilding> getBuildListSortByProduct(Integer version) {
        return baseMapper.getBuildListSortByBuilding(version);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:by:build", key = "#build")
    public List<RecipeVO> getRecipeByBuildingId(Integer build) {
        if (build == null) return null;
        return baseMapper.getRecipeByBuildingId(build);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:by:ingredient", key = "#item")
    public List<RecipeVO> getRecipeByIngredientId(Integer item) {
        if (item == null) return null;
        return baseMapper.getRecipeByIngredientId(item);
    }

    @Override
    @Cacheable(cacheNames = "recipe:list:by:product", key = "#item")
    public List<RecipeVO> getRecipeByProductId(Integer item) {
        if (item == null) return null;
        return baseMapper.getRecipeByProductId(item);
    }
    @Override
    @Cacheable(cacheNames = "recipe:list:cal:item", key = "#version + '&' + #item")
    public List<calRecipe> getCalRecipeByItem(Integer version, Integer item) {
        List<calRecipe> list = baseMapper.getCalRecipeByItem(version, item);
        list.forEach(((calRecipe) -> {
            calRecipe.setIngredients(baseMapper.getCalIngredientsById(calRecipe.getId()));
            calRecipe.setProducts(baseMapper.getCalProductsById(calRecipe.getId()));
        }));
        return list;
    }

    @Override
    @Cacheable(cacheNames = "cal:recipe", key = "#item + '-' + #id")
    public List<DoublePair> getFactoryRecipeById(Integer item, Integer id) {
//        System.out.print(item + " ");
        List<DoublePair> recipe = baseMapper.getFactoryRecipeById(id);
        recipe.removeIf(Objects::isNull);// 删除null的查询记录

        double mul = 0;
        int index = 0;
        //进行配方处理
        for (int i = 0; i < recipe.size(); i++) {
            if (Objects.equals(recipe.get(i).getId(), item)) {
                mul = -1 / recipe.get(i).getNumber();
                index = i;
                break;
            }
        }
        recipe.remove(index); // 删除目标元素
        for (DoublePair i : recipe) i.setNumber(i.getNumber() * mul);
        return recipe;
    }

    @Override
    @Cacheable(cacheNames = "tran:recipe", key = "#recipe + '-' + #item")
    public TranslationRecipe getTranslationRecipe(int item, int recipe) {
        return baseMapper.getTranslationRecipe(item, recipe);
    }

    @Override
    @Cacheable(cacheNames = "recipe:vo", key = "#id")
    public RecipeVO getRecipeVOById(Integer id) {
        if (id == null) return null;
        return baseMapper.getRecipeVOById(id);
    }
}




